using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.ComponentModel;
using System.Linq;
using MySQLStudio.ComponentModel;
using System.Drawing.Design;
using MySQLStudio.BusinessLogic.ComponentModel;
using MySQLStudio.Common;
using MySQLStudio.Common.Data;

namespace MySQLStudio.BusinessLogic
{
    [TypeDescriptionProvider(typeof(ColumnTypeDescriptionProvider))]
	public class Column : BaseDatabaseObject, IEditableObject, IEqualityComparer<Column>
	{
		private IColumnsContainer m_container;        
        private bool m_isIdentity;
		private bool m_inPrimaryKey;
        private string m_providerType = string.Empty;
		private string m_datatype;
        private bool m_unsigned;
        private string m_default;
        private string m_collation;
        private bool m_isNullable;
        private ulong? m_length;
        private ulong? m_precision;
        private ulong? m_scale;
        private bool m_zerofill;        
        private string m_comment;
        private bool m_isPersisted;        

        public event EventHandler<ColumnChangedEventArgs> ColumnChanged;

        private Column m_backupColumn;               

        public Column(IColumnsContainer container)
            : this()
        {
            this.m_container = container;           
        }

        public Column()
        {
            DbDataType dataType = DataUtils.DataTypes.FirstOrDefault(dt => dt.Name == "int");

            this.m_isIdentity = false;
            this.m_inPrimaryKey = false;
            this.m_datatype = dataType.Name;
            this.m_default = null;
            this.m_unsigned = false;
            this.m_collation = null;
            this.m_isNullable = true;
            this.m_length = dataType.Length;
            this.m_precision = dataType.Precision;
            this.m_scale = dataType.Scale;
            this.m_comment = string.Empty;
            this.m_backupColumn = null;
            this.m_isPersisted = false;            
        }

        internal Column BackupColumn
        {
            get
            {
                return m_backupColumn;
            }
        }

        [Browsable(false)]
        public IColumnsContainer Container
        {
            get
            {
                return this.m_container;
            }
            set
            {
                this.m_container = value;
            }
        }

        [Category("(General)")]
        public override string Name
        {
            get
            {
                return base.Name;
            }
            set
            {
                base.Name = value;                
                
                if (this.ColumnChanged != null)
                {
                    this.ColumnChanged(this, new ColumnChangedEventArgs(this));
                }
            }
        }

        [Category("Table Designer")]
		public bool InPrimaryKey
		{
            get
            {
                return this.m_inPrimaryKey;
            }
            set
            {
                this.m_inPrimaryKey = value;                

                if (this.ColumnChanged != null)
                {
                    this.ColumnChanged(this, new ColumnChangedEventArgs(this));
                }
            }
		}

        [Category("Table Designer")]
		public bool IsIdentity
		{
            get
            {
                return this.m_isIdentity;
            }
            set
            {
                this.m_isIdentity = value;                

                if (this.ColumnChanged != null)
                {
                    this.ColumnChanged(this, new ColumnChangedEventArgs(this));
                }
            }
		}       

        [Editor(typeof(ListGridComboBox), typeof(UITypeEditor))]
        [DataList("MySQLStudio.Common", "MySQLStudio.Common.DataUtils", "DataTypes.DataTypes", false)]
        [Category("(General)")]
		public string DataType
		{
            get
            {
                return this.m_datatype;
            }
            set
            {
                this.m_datatype = value;

                DbDataType dataType = DataUtils.DataTypes.FirstOrDefault(dt => dt.Name == value);

                this.Length = dataType.Length;
                this.Precision = dataType.Precision;
                this.Scale = dataType.Scale;

                if (this.ColumnChanged != null)
                {
                    this.ColumnChanged(this, new ColumnChangedEventArgs(this));
                }
            }
		}

        [Category("Table Designer")]
        public bool Unsigned
        {
            get
            {
                return this.m_unsigned;
            }
            set
            {
                this.m_unsigned = value;                

                if (this.ColumnChanged != null)
                {
                    this.ColumnChanged(this, new ColumnChangedEventArgs(this));
                }
            }
        }

        [Category("Table Designer")]
        public bool Zerofill
        {
            get
            {
                return this.m_zerofill;
            }
            set
            {
                this.m_zerofill = value;
                
                if (this.ColumnChanged != null)
                {
                    this.ColumnChanged(this, new ColumnChangedEventArgs(this));
                }
            }
        }

        [Category("(General)")]
        [DisplayName("Default Value")]
        public string Default
        {
            get
            {
                return this.m_default;
            }
            set
            {
                this.m_default = value;                

                if (this.ColumnChanged != null)
                {
                    this.ColumnChanged(this, new ColumnChangedEventArgs(this));
                }
            }
        }

        [Browsable(true)]        
        [Editor(typeof(ListGridComboBox), typeof(UITypeEditor))]
        [DataList("MySQLStudio.Common", "MySQLStudio.Common.Data.Collations", "ServerCollations", false)]
        [Category("Table Designer")]
        public string Collation
        {
            get
            {
                return this.m_collation;
            }
            set
            {
                this.m_collation = value;
                
                if (this.ColumnChanged != null)
                {
                    this.ColumnChanged(this, new ColumnChangedEventArgs(this));
                }
            }
        }

        [Category("(General)")]
        [DisplayName("Allow Nulls")]        
        public bool IsNullable
        {
            get
            {
                return m_isNullable;
            }
            set
            {
                m_isNullable = value;                

                if (this.ColumnChanged != null)
                {
                    this.ColumnChanged(this, new ColumnChangedEventArgs(this));
                }
            }
        }        

        [Category("Table Designer")]        
        public ulong? Length
        {
            get
            {
                return m_length;

                if (this.ColumnChanged != null)
                {
                    this.ColumnChanged(this, new ColumnChangedEventArgs(this));
                }
            }
            set
            {
                m_length = value;                

                if (this.ColumnChanged != null)
                {
                    this.ColumnChanged(this, new ColumnChangedEventArgs(this));
                }
            }
        }

        [Browsable(false)]
        public bool IsPersisted
        {
            get
            {
                return m_isPersisted;
            }
            internal set
            {
                m_isPersisted = value;
            }
        }

        [Browsable(false)]
        public bool IsChanged
        {
            get
            {
                return this.m_backupColumn != null
                    && !this.Equals(this.m_backupColumn);
            }            
        }

        [Category("Table Designer")]
        public ulong? Precision
        {
            get
            {
                return m_precision;
            }
            set
            {
                m_precision = value;                

                if (this.ColumnChanged != null)
                {
                    this.ColumnChanged(this, new ColumnChangedEventArgs(this));
                }
            }
        }

        [Category("Table Designer")]
        public ulong? Scale
        {
            get
            {
                return m_scale;
            }
            set
            {
                m_scale = value;                

                if (this.ColumnChanged != null)
                {
                    this.ColumnChanged(this, new ColumnChangedEventArgs(this));
                }
            }
        }

        [Category("Table Designer")]
        public string Comment
        {
            get
            {
                return m_comment;
            }
            set
            {
                m_comment = value;                

                if (this.ColumnChanged != null)
                {
                    this.ColumnChanged(this, new ColumnChangedEventArgs(this));
                }
            }
        }

        #region IEditableObject Members

        void IEditableObject.BeginEdit()
        {
            if (this.m_backupColumn == null && this.IsPersisted)
            {
                this.m_backupColumn = new Column();

                this.CopyTo(this.m_backupColumn);
            }
        }

        void IEditableObject.CancelEdit()
        {
            this.m_backupColumn.CopyTo(this);
        }

        void IEditableObject.EndEdit()
        {
            //this.m_backupColumn = null;
        }

        #endregion        

        public void CopyTo(Column target)
        {
            target.Collation = this.Collation;
            target.Comment = this.Comment;
            target.Container = this.Container;
            target.DataType = this.DataType;
            target.Default = this.Default;
            target.InPrimaryKey = this.InPrimaryKey;            
            target.IsIdentity = this.IsIdentity;
            target.IsNullable = this.IsNullable;
            target.Length = this.Length;
            target.Name = this.Name;
            target.Precision = this.Precision;           
            target.Scale = this.Scale;
            target.Schema = this.Schema;
            target.Type = this.Type;
            target.Unsigned = this.Unsigned;
        }

        private void OnColumnChanged()
        {
            if (ColumnChanged != null)
            {
                this.ColumnChanged(this, new ColumnChangedEventArgs(this));
            }
        }

        public void Rename(Host host, Database database, string newName)
        {
            Table table = this.Container as Table;

            if (table != null && table.IsPersisted)
            {
                TablesController.RenameColumn(host.ConnectionString, database.Name, table.Name, this, newName);
            }

            this.Name = newName;
        }

        public override bool Equals(object obj)
        {
            return (obj is Column) && this.Equals(this, (Column)obj);
        }

        public override int GetHashCode()
        {
            return this.GetHashCode(this);
        }

        public override string ToString()
        {
            return string.Format("Name: {0}; DataType: {1}", this.Name, this.DataType);
        }

        #region IEqualityComparer<Column> Members

        public bool Equals(Column x, Column y)
        {
            if (x == null && y == null)
            {
                return true;
            }

            return x != null
                && y != null
                && x.Name == y.Name
                && x.Collation == y.Collation
                && x.Comment == y.Comment
                && x.DataType == y.DataType
                && x.Default == y.Default
                && x.InPrimaryKey == y.InPrimaryKey
                && x.IsIdentity == y.IsIdentity
                && x.IsNullable == y.IsNullable
                && x.Length == y.Length                
                && x.Precision == y.Precision
                && x.Scale == y.Scale
                && x.Schema == y.Schema
                && x.Type == y.Type
                && x.Unsigned == y.Unsigned
                && x.Zerofill == y.Zerofill;                
        }

        public int GetHashCode(Column obj)
        {
            return (obj.Name + obj.Collation + obj.Comment + obj.DataType + obj.Default
                + obj.InPrimaryKey + obj.IsIdentity + obj.IsNullable + obj.Length + obj.Precision
                + obj.Scale + obj.Scale + obj.Schema + obj.Type + obj.Unsigned + obj.Zerofill).GetHashCode();
        }

        #endregion

        internal void Commit()
        {
            this.IsPersisted = true;
            this.m_backupColumn = null;            
        }
    }
}
